use std::any::Any;

use futures::Future;


#[derive(Debug, thiserror::Error, PartialEq)]
pub enum FError {
}

pub trait CallContext: Send + Sync {
    fn get(&self, key: String) -> Result<Box<dyn Any>, FError>;
}

struct EmptyCallContext;

impl CallContext for EmptyCallContext {
    fn get(&self, key: String) -> Result<Box<dyn Any>, FError> {
        Ok(Box::new(()))
    }
}



pub trait CallCore<T: Send, R: Send> : Send + Sync {
    async fn run(&self, arg: T, ctx: Box<dyn CallContext>) -> Result<R, FError>;
}

pub struct Composer {
}

impl Composer {
    pub fn from_fn<T: Send + Sync, R: Send + Sync, F, Fut>(f: F) -> impl CallCore<T, R>
    where
        Fut: Future<Output = Result<R, FError>> + Send + Sync,
        F: Fn(T, Box<dyn CallContext>) -> Fut + Send + Sync,
    {
        struct FnCallCore<F, Fut> {
            f: F,
            _phantom: std::marker::PhantomData<Fut>,
        }

        impl<T, R, F, Fut> CallCore<T, R> for FnCallCore<F, Fut>
        where
            T: Send,
            R: Send,
            Fut: Future<Output = Result<R, FError>> + Send + Sync,
            F: Fn(T, Box<dyn CallContext>) -> Fut + Send + Sync,
        {
            async fn run(&self, arg: T, ctx: Box<dyn CallContext>) -> Result<R, FError> {
                let data = ctx.get("".to_string())?;
                (self.f)(arg, ctx).await 
            } 
        }
        FnCallCore { f, _phantom: std::marker::PhantomData }
    }

}




#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn from_fn() {
        let f = Composer::from_fn(async |arg: i32, ctx: Box<dyn CallContext>| {
            ctx.get("".to_string())?;
            Ok(arg + 1)
        });
    }

    #[tokio::test]
    async fn test_copy2() {
        let f = Composer::from_fn(async |arg: i32, _: Box<dyn CallContext>| {
            Ok(arg + 1)
        });
    }

    #[tokio::test]
    async fn test_copy() {
        trait IsClone {
            fn is_clone() -> bool;
        }

        impl<T> IsClone for T {
            default fn is_clone() -> bool {
                false
            }
        }
        
        impl<T: Clone> IsClone for T {
            fn is_clone() -> bool {
                true
            }
        } 

        fn sss<T>(t: T) {
            println!("T is Clone: {}", <T as IsClone>::is_clone());
        }

        sss(1);
        sss("1");
        sss(vec![1, 2, 3]);
        sss(Composer::from_fn(async |arg: i32, _: Box<dyn CallContext>| {
            Ok(arg + 1)
        }));
    }



}
